//////////////////////////////////////////////////////////////////////////////
//    Copyright 2004, SenseGraphics AB
//
//    This file is part of H3D API.
//
//    H3D API is free software; you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation; either version 2 of the License, or
//    (at your option) any later version.
//
//    H3D API is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with H3D API; if not, write to the Free Software
//    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//    A commercial license is also available. Please contact us at 
//    www.sensegraphics.com for more information.
//
//
/// \file GeoDeformableShape.h
/// \brief Header file for GeoDeformableShape
///
//
//////////////////////////////////////////////////////////////////////////////
#ifndef __GEODEFORMABLESHAPE_H__
#define __GEODEFORMABLESHAPE_H__

#include "X3DShapeNode.h"
#include "Coordinate.h"
#include "IndexedFaceSet.h"
#include "IndexedTriangleFanSet.h"
#include "IndexedTriangleSet.h"
#include "IndexedTriangleStripSet.h"
#include "TriangleFanSet.h"
#include "TriangleSet.h"
#include "TriangleStripSet.h"
#include "GeoH3DNeighboursNode.h"
#include "GeoH3DCoordinateDeformerNode.h"

//Mike Oren: added this to use ImageTexture as haptic/sound texture
#include "ImageTexture.h"
#include "X3DComposedGeometryNode.h"

namespace H3D {

  /// \ingroup H3DNodes
  /// \brief The GeoDeformableShape is an X3DShapeNode which makes it possible
  /// to deform the geometry of the shape when touching it with a haptics
  /// device.
  ///
  /// The deformer field specifies an H3DCoordinateDeformerNode that 
  /// determines how the coordinates should be deformed on contact.
  /// If NULL, no deformation will be done.
  ///
  /// The geometry field must contain an X3DComposedGeometryNode, and the 
  /// coordinates in its coord field are the ones that will be deformed.
  /// 
  /// The origCoord field contains the coordinates that the 
  /// X3DComposedGeometryNode had when it was added to the 
  /// X3DComposedGeometryNode. These are the coordinates that was used 
  /// before any deformation started.
  ///
  /// The deformedCoord field contains the coordiates after deformation of
  /// current contacts of haptics devices. These are the coordinates that 
  /// will be used for graphics rendering.
  ///
  /// The restingCoord fields contain the coordinates that the geometry will
  /// go back to when there are no contacts to the geometry any longer. If
  /// the deformation is non-plastic, this will be the same as origCoord.
  
  class H3DAPI_API GeoDeformableShape : public X3DShapeNode {
  public:
    typedef TypedSFNode< Coordinate > SFCoordinateNode;
    typedef TypedSFNode< GeoH3DCoordinateDeformerNode > SFCoordinateDeformer;
    typedef DependentSFNode< GeoH3DNeighboursNode,
                             FieldRef< X3DGeometricPropertyNode,
                             Field,
                             &GeoH3DNeighboursNode::propertyChanged > > 
    SFNeighboursNode;

    /// The SFGeometryNode is extended to only accept X3DComposedGeometryNode
    /// nodes.
    class SFGeometryNode: public X3DShapeNode::SFGeometryNode {
	friend class GeoDeformableShape;
	protected :
	  /// First step to determine neighbours per vertex. It computes faces according to coordinates which establish them.
	  /// \param n Node which has got information to compute coordinates per face.
	  /// \return List of the faces described thanks to their coordinates indexes.
	  virtual vector<vector< unsigned long > > coordinateIndexPerFace( IndexedFaceSet* n );

	  /// First step to determine neighbours per vertex. It computes faces according to coordinates which establish them.
	  /// \param n Node which has got information to compute coordinates per face.
	  /// \return List of the faces described thanks to their coordinates indexes.
	  virtual vector<vector< unsigned long > > coordinateIndexPerFace( IndexedTriangleFanSet* n );

	  /// First step to determine neighbours per vertex. It computes faces according to coordinates which establish them.
	  /// \param n Node which has got information to compute coordinates per face.
	  /// \return List of the faces described thanks to their coordinates indexes.
	  virtual vector<vector< unsigned long > > coordinateIndexPerFace( IndexedTriangleSet* n );

	  /// First step to determine neighbours per vertex. It computes faces according to coordinates which establish them.
	  /// \param n Node which has got information to compute coordinates per face.
	  /// \return List of the faces described thanks to their coordinates indexes.
	  virtual vector<vector< unsigned long > > coordinateIndexPerFace( IndexedTriangleStripSet* n );

	  /// First step to determine neighbours per vertex. It computes faces according to coordinates which establish them.
	  /// \param n Node which has got information to compute coordinates per face.
	  /// \return List of the faces described thanks to their coordinates indexes.
	  virtual vector<vector< unsigned long > > coordinateIndexPerFace( TriangleFanSet* n );

	  /// First step to determine neighbours per vertex. It computes faces according to coordinates which establish them.
	  /// \param n Node which has got information to compute coordinates per face.
	  /// \return List of the faces described thanks to their coordinates indexes.
	  virtual vector<vector< unsigned long > > coordinateIndexPerFace( TriangleSet* n );

	  /// First step to determine neighbours per vertex. It computes faces according to coordinates which establish them.
	  /// \param n Node which has got information to compute coordinates per face.
	  /// \return List of the faces described thanks to their coordinates indexes.
	  virtual vector<vector< unsigned long > > coordinateIndexPerFace( TriangleStripSet* n );

	  /// Second step to determine neighbours per vertex. It computes neighbours per vertex from a list of faces described thanks to indexes of their coordinates.
	  /// This process is independent from the shape representation instead of the first step carried out with coordinateIndexPerFace.
	  /// \param indexPerFace List of the faces described thanks to their coordinates indexes.
	  /// \return Neighbourhood information for all shape coordinates.
	  virtual GeoH3DNeighboursNode *generateNeighbours(
						const vector< vector< unsigned long > > &
						indexPerFace );

      /// Destructor. Sets the value to NULL in order to get the correct
      /// onAdd and onRemove functions to be called and initialize the 
      /// different coord fields in the GeoDeformableShape node when changing
      /// the geometry.
      ~SFGeometryNode() {
        value = NULL;
      }

      virtual void onAdd( Node *n );

	  auto_ptr< GeoH3DNeighboursNode > neighbourhood;
    };

    /// Constructor.       
    GeoDeformableShape( Inst< SFAppearanceNode > _appearance     = 0,
                     Inst< SFGeometryNode   > _geometry       = 0,
                     Inst< SFHapticGeometry > _hapticGeometry = 0,
                     Inst< SFNode           > _metadata       = 0,
                     Inst< SFBound          > _bound          = 0,
                     Inst< SFVec3f          > _bboxCenter     = 0,
                     Inst< SFVec3f          > _bboxSize       = 0,
                     Inst< SFCoordinateNode > _origCoord      = 0,
                     Inst< SFCoordinateNode > _restingCoord   = 0,
                     Inst< SFCoordinateNode > _deformedCoor   = 0,
                     Inst< SFCoordinateDeformer > _deformer   = 0,
					 Inst< SFBool > _shouldDeform			  = 0,
					 Inst< SFBool > _isGrasping               = 0,
					 Inst< SFString > _hapImg			      = 0,
					 Inst< SFString > _sndImg				  = 0,
					 Inst< SFBool > _shouldDraw				  = 0,
					 Inst< SFFloat > _velocity				  = 0,
					 Inst< SFFloat > _key					  = 0,
					 Inst< SFFloat > _hue					  = 0,
					 Inst< SFFloat > _saturation			  = 0,
					 Inst< SFFloat > _intensity				  = 0);

	virtual ~GeoDeformableShape();
    
    /// Traverse the scenegraph. The deformation parameters are updated
    /// in the CoordinateDeformer in coordinateDeformer field.
    virtual void traverseSG( TraverseInfo &ti );
	
    /// The origCoord field contains the coordinates that the 
    /// X3DComposedGeometryNode had when it was added to the 
    /// X3DComposedGeometryNode. These are the coordinates that was used 
    /// before any deformation started.
    ///
    /// <b> Access type: </b> outputOnly
    auto_ptr< SFCoordinateNode > origCoord;

    /// The restingCoord fields contain the coordinates that the geometry will
    /// go back to when there are no contacts to the geometry any longer. If
    /// the deformation is non-plastic, this will be the same as origCoord.
    ///
    /// <b> Access type: </b> outputOnly
    auto_ptr< SFCoordinateNode > restingCoord;

    /// The deformedCoord field contains the coordiates after deformation of
    /// current contacts of haptics devices. These are the coordinates that 
    /// will be used for graphics rendering.
    ///
    /// <b> Access type: </b> outputOnly
    auto_ptr< SFCoordinateNode > deformedCoord;   

    /// The deformer field specifies an H3DCoordinateDeformerNode that 
    /// determines how the coordinates should be deformed on contact.
    /// If NULL, no deformation will be done.
    auto_ptr< SFCoordinateDeformer > deformer;   

	// Jon Sheller
	// Value to decide if deformation should occur
	auto_ptr< SFBool > shouldDeform;

	//Mike Oren
	//Value to decide if the current surface is being grasped.
	auto_ptr< SFBool > isGrasping;

	//Mike Oren
	//Haptic/Audio texture
	auto_ptr< SFString> hapImg;
	auto_ptr< SFString> sndImg;

	//Mike Oren
	//Value to decide if points should be drawn on the image texture.
	auto_ptr< SFBool > shouldDraw;
	auto_ptr< SFFloat > velocity;
	auto_ptr< SFFloat > key;
	//Mike Oren: HSL values
	auto_ptr< SFFloat > hue;
	auto_ptr< SFFloat > saturation;
	auto_ptr< SFFloat > intensity;

    /// The H3DNodeDatabase for this node.
    static H3DNodeDatabase database;

	// Jon Sheller
	// Helper function to get color of contact point
	bool GetContactColor(X3DComposedGeometryNode *geom, vector<DWORD> & colors, ImageTexture *tex);

	//Mike Oren
	//Draws a point on the image at the contact point.
	void SetContactColor(X3DComposedGeometryNode *geom, Vec3f thicknessVec);
  };
}

#endif
